<template>
  <div style="width: 100%">
    <span v-if="showText">{{ formData[prop + '_name'] || '' }}</span>
    <el-select
      v-else
      ref="selectRef"
      v-model="currValue"
      class="select"
      :multiple="multiple"
      :filterable="filterable"
      :placeholder="calcPlaceholder"
      :disabled="calcDisabled"
      @change="handleChange"
      clearable
      collapse-tags
      collapse-tags-tooltip
    >
      <template #label="{value}">
        <span v-html="formatHtml(value)" />
      </template>
      <el-option
        v-for="item in options"
        :key="item.key"
        :value="item.key"
        :label="item.value + '@' + item.color"
        :disabled="item.disabled === true"
      >
        <span
          v-if="item.color"
          class="cc-dict-label"
          :style="'background: ' + item.color"
        >{{item.value}}</span>
        <span v-else>{{item.value}}</span>
      </el-option>
    </el-select>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, computed, inject, onUnmounted } from 'vue';
import { getDictionary } from '@/utils/system';
import { useDisabled } from 'element-plus';
import emitter from "@/utils/bus";
import tool from "@/utils/tool";

const emit = defineEmits(['change']);
const props = defineProps({
  prop: {
    type: String,
    default: ''
  },
  dictCode: String,
  queryList: Object,
  filterable: {
    type: Boolean,
    default: true,
  },
  multiple: {
    type: Boolean,
    default: false,
  },
  placeholder: {
    type: String,
    default: '--请选择--'
  },
  disabled: Boolean,
  showText: Boolean
})

const currValue = ref();
const formData = inject('formData');
const selectRef = ref();
const loading = ref(true);
const allOptions = ref([]);
const options = ref([]);
const inputDisabled = useDisabled();

const init = () => {
  loadDicAndShow(props.dictCode);
};

const handleChange = () => {
  if (props.multiple) {
    formData.value[props.prop] = currValue.value ? currValue.value.join(',') : '';
  } else {
    formData.value[props.prop] = currValue.value || '';
  }

  emit('change');
};

const loadDicAndShow = async(dictCode) => {
  if ((dictCode || '') === '') {
    allOptions.value = [];
    options.value = [];
  } else {
    loading.value = true;
    allOptions.value = await getDictionary(dictCode);
    loading.value = false;
    initCurrValue();
  }
};

const filter = (list, queryList) => {
  if (!list || list.length === 0 || !queryList || queryList.length === 0) return list || [];
  return list.filter(item => queryList.every(query => {
    if (query.filterValue) {
      return item[query.filterFieldId] === query.filterValue;
    } else {
      return item[query.filterFieldId] === formData.value[query.dataFieldName];
    }
  }));
};

const calcPlaceholder = computed(() => {
  return (inputDisabled.value || props.disabled) ? '' : props.placeholder;
});

const calcDisabled = computed(() => {
  return inputDisabled.value || props.disabled;
});

const formatHtml = (value) => {
  const option = options.value.find(item => item.key === value);

  return option && option.color ? `
    <span
      class="cc-dict-label"
      style="background: ${option.color}"
    >${option.value}</span>
  ` : `<span>${option?.value}</span>`;
}

const initCurrValue = () => {
  options.value = filter(allOptions.value, props.queryList);
  if (props.multiple) {
    currValue.value = formData.value[props.prop] ? (formData.value[props.prop] || '').split(',') : [];
    if (!loading.value) {
      for (let value of currValue.value) {
        if (!options.value.find(item => item.key === value)) {
          currValue.value = [];
          return;
        }
      }
    }
  } else {
    currValue.value = formData.value[props.prop] || '';
    if (!loading.value && !options.value.find(item => item.key === currValue.value)) {
      currValue.value = '';
    }
  }
};

watch(() => tool.deepClone(formData.value), () => {
  initCurrValue();
}, {immediate: true});

watch(() => props.dictCode, () => {
  init();
}, {immediate: true});

onMounted(() => {
  emitter.off("dictionary.change", init);
  emitter.on("dictionary.change", init);
});

onUnmounted(() => {
  emitter.off("dictionary.change", init);
});
</script>

<style scoped>
.select {
  width: 100%;
}
.select :deep(.el-select__selection) {
  flex-wrap: nowrap;
}
</style>